// #include "util.h"
// #include "config.h"
// #include <chrono>
// #include <cstdarg>
// #include <cstdio>
// #include <cstdlib>
// #include <ctime>
// #include <iostream>
// #include <netinet/in.h>
// #include <random>
// #include <sys/socket.h>
// #include <thread>
// #include <unistd.h>
// #include <x86_64-linux-gnu/bits/types/struct_tm.h>

// //改参数用来调试程序，例如，如果日志队列为空，线程阻塞，我们可以使用该函数，在if里面打印为空的时间和阻塞的线程。
// void Dprintf( const char *format, ... )
// {
//     if ( Debug )
//     {
//         //获取当前信息，不需要操作信息和对精度要求不高则可以使用time函数
//         time_t now = time( nullptr );  //这里获取的是从1970年到现在的秒数。
//         //将其填入到tm结构体中
//         tm *nowtm = localtime( &now );

//         //初始化可变参数列表
//         va_list args;  //定义可变参数列表
//         va_start( args, format );
//         //将可变参数列表args设置为指向紧随format之后的第一个可变参数，可以用来确定在栈上可变参数的起始位置

//         //这是打印当前的时间
//         std::printf( "[%d-%d-%d-%d-%d]", nowtm->tm_year + 1900, nowtm->tm_mon + 1, nowtm->tm_mday, nowtm->tm_min, nowtm->tm_sec );

//         //按照指定格式打印可变参数列表中的参数，即使用格式化打印参数
//         std::vprintf( format, args );
//         /*
//             vprintf的使用需要和可变参数列表同时使用 var_list var_start var_end
//         */
//         std::printf( "\n" );

//         //
//         va_end( args );
//     }
// }

// /*
//     用来防止程序出现意外的错误，例如出现了网络分区，此时打印错误信息，并立即终端程序，但是需要注意资源的释放情况。
//     std::exit( EXIT_FAILURE );会自动释放全局的对象的析构函数，来释放资源，
//     但是局部对象的析构函数并不会被调用。此时需要处理局部资源的释放,局部资源释放函数，用来处理std::exit错误退出时的局部资源释放
//     我们需要设计局部资源释放，可以使用lambda表示式作为参数，传递给myseert，在条件不成立，中断程序时，释放局部资源，
//     因此，第三个参数为std::function来包装任意的函数调用对象
//     在使用是可以传一个lambda表达式
// */
// void myAssert( bool condition, std::string message )
// {
//     if ( !condition )
//     {
//         std::cerr << "Error:" << message << std::endl;

//         // EXIT_FAILURE：表示程序因意外而退出，以之对应的是EXIT_SUCCESS：表示程序成功结束
//         std::exit( EXIT_FAILURE );
//     }
// }

// //获取高精度时间
// std::chrono::_V2::system_clock::time_point now() { return std::chrono::high_resolution_clock::now(); }

// //随机选举超时时间
// /*
// 执行步骤：
// 1、创建random_device随机数生成器对象
// 2、利用rd()生成的种子来初始化mt19937 随机数。
// 3、定义一个随机数分布区间，dist是均匀分布的区间。
// 4、dist(rng)：将生成的随机数rng转换为区间内的随机数
// 5、构造一个std::chrono::milliseconds对象初始化后并返回。
// 此时函数就能获得一个在区间内的随机毫秒值。
// */
// std::chrono::microseconds getRandomizedElectionTimeout()
// {

//     //创建一个随机数生成器对象，在这里使用rd是使其来生成下一个随机数的种子
//     std::random_device rd;
//     // rd使用默认构造生成一个随机值，这个随机值给rng充当随机数生成器的种子。因为std::mt19937需要一个种子值来进行初始化。
//     std::mt19937 rng( rd() );

//     //通常做法是使用std::random_device作为一个高质量的种子的来源来初始化一个更快、功能更强大的伪随机数生成器，如
//     // std::mt19937
//     std::uniform_int_distribution< int > dist( minRandomizedElectionTime, maxRandomizedElectionTime );
//     return std::chrono::microseconds( dist( rng ) );
// }

// //定义休眠
// void sleepNMilliseconds( int n ) { std::this_thread::sleep_for( std::chrono::microseconds( n ) ); }

// //判断端口是否占用
// bool isReleasePort( unsigned short usport )
// {
//     int s = socket( AF_INET, SOCK_STREAM, 0 );
//     if ( s < 0 )
//     {
//         return false;  // Socket creation failed
//     }
//     struct sockaddr_in addr;
//     addr.sin_family = AF_INET;
//     addr.sin_port = htons( usport );
//     addr.sin_addr.s_addr = htonl( INADDR_LOOPBACK );
//     int ret = bind( s, ( struct sockaddr * )&addr, sizeof( addr ) );
//     if ( ret != 0 )
//     {
//         close( s );
//         return false;
//     }

//     close( s );
//     return true;
// }

// //获取未使用的端口号,最大次数为30次
// bool getReleasePort( short &port )
// {
//     short tmp = port;
//     short num = 0;
//     while ( !isReleasePort( port ) && num < 30 )
//     {
//         ++port;
//         ++num;
//     }
//     if ( num >= 30 )
//     {
//         std::cout << "在端口" << tmp << "到端口" << port << "之间没有可用的端口号" << std::endl;
//         port = -1;
//         return false;
//     }
//     return true;
// }